package com.hd.trans.network.component

import android.content.Context
import android.text.TextUtils
import android.util.Log
import android.util.SparseArray
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import com.hd.trans.R
import com.hd.trans.TranslationInterior
import com.hd.trans.common.Constants
import com.hd.trans.network.ApiServiceManager
import com.hd.trans.network.MultNetDisposableObserver
import com.hd.trans.network.RxSchedulers
import com.hd.trans.network.bean.MultDataResponse2
import com.hd.trans.network.bean.trans.TextTransNewReq
import com.hd.trans.network.bean.trans.TextTransNewRes
import com.hd.trans.offline.OfflineDisposableObserver
import com.hd.trans.share.Md5Util
import com.hd.trans.ui.base.AppContextProvider
import com.hd.trans.utils.CommonUtil
import com.hd.trans.utils.OfflineConstant
import com.hd.trans.utils.StringUtils
import com.translation.assistant.data.bean.TransResultBean
import com.translation.assistant.manager.OfflineTranslatorManager
import com.translation.assistant.utils.SensitiveWordsCheck
import io.reactivex.Observable
import io.reactivex.ObservableEmitter
import io.reactivex.ObservableOnSubscribe
import io.reactivex.functions.Function
import io.reactivex.schedulers.Schedulers
import java.util.TreeMap

class HdTranslateComponent: LifecycleObserver {

    private var offlineManager: OfflineTranslatorManager
    private var isDestroy: Boolean = false
    private var mContext: Context

    constructor() {
        this.mContext = AppContextProvider.getContext()
        offlineManager = OfflineTranslatorManager.getInstance(mContext)
    }

    constructor(context: Context) {
        this.mContext = context
        offlineManager = OfflineTranslatorManager.getInstance((mContext))
    }

    /**
     * 页面销毁 终止回调
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destroy() {
        isDestroy = true
        offlineManager.destroy()
    }

    fun translationText(
        context: Context,
        origContent: String?,
        fromTranslateCode: String,
        toTranslateCode: String,
        isOpenOfflineTrans: Boolean = false,
        callback: TranslateCallback?
    ) {
        this.mContext = context
        translationText(origContent, fromTranslateCode, toTranslateCode, isOpenOfflineTrans, callback)
    }

    fun translationText(
        origContent: String?,
        fromTranslateCode: String,
        toTranslateCode: String,
        isOpenOfflineTrans: Boolean = false,
        callback: TranslateCallback?
    ) {
        //输入文本翻译前处理
        var origContentAfter = origContent
        if (origContentAfter == null || StringUtils.isEmpty(origContentAfter)) {
            callback?.onTranslateFailed(
                Constants.ResponseCode.ERROR_COMM,
                mContext.getString(R.string.tips_empty_content)
            )
            return
        }
        if (fromTranslateCode == "en") {
            //英文翻译时，将下划线替换为中划线，否则内容翻译不了
            origContentAfter = origContentAfter.replace("_", "-")
        }

        if(isOpenOfflineTrans){
            //离线翻译
            offlineManager.checkLanguageCode(fromTranslateCode){ hadFromCode ->//是否下载了源语言离线包
                if(hadFromCode){
                    offlineManager.checkLanguageCode(toTranslateCode){ hadToCode ->//是否下载了目标语言离线包
                        if(hadToCode){
                            translateOffline(origContentAfter, fromTranslateCode, toTranslateCode, callback)
                        }else{
                            //自动下载离线包
                            offlineManager.downloadModel(toTranslateCode)
                            //转在线翻译
                            translateOnline(origContentAfter, fromTranslateCode, toTranslateCode, false, callback)
                        }
                    }
                }else{
                    //自动下载离线包
                    offlineManager.downloadModel(fromTranslateCode)
                    //转在线翻译
                    translateOnline(origContentAfter, fromTranslateCode, toTranslateCode, false, callback)
                }
            }
        }else{
            //在线翻译
            translateOnline(origContentAfter, fromTranslateCode, toTranslateCode, false, callback)
        }
    }

    /**文本快捷翻译（新接口）*/
    private fun translateOnline(
        origContentAfter: String,
        fromLang: String,
        toLang: String,
        withDiff: Boolean = false,
        callback: TranslateCallback?
    ) {
        if (OfflineConstant.checkNetwork(AppContextProvider.getContext()) == OfflineConstant.NETWORL_NONE) {
            //无网络
            callback?.onTranslateFailed(
                Constants.ResponseCode.ERROR_NETWORK,
                mContext.getString(R.string.no_network_prompt)
            )
            return
        }

        val contentList = StringUtils.splitStringByLength(origContentAfter, Constants.MAX_TRANSLATE_SIZE)
        if (contentList.isNullOrEmpty()) {
            callback?.onTranslateFailed(
                Constants.ResponseCode.ERROR_COMM,
                mContext.getString(R.string.tips_empty_content)
            )
            return
        }

        val size = contentList.size
        val observables: Array<Observable<*>?> = arrayOfNulls(size)
        for (i in contentList.indices) {
            val req = TextTransNewReq()
            req.fromLang = fromLang
            req.toLang = toLang
            req.fromText = contentList[i]
            req.timestamp = CommonUtil.getServiceTimeStamp()
            req.withDiff = withDiff
            req.sign = sortByKey(req)
            observables[i] = ApiServiceManager.transitionNewApi
                .tansTextQuick(req)
                .map(Function { data: TextTransNewRes? ->
                    MultDataResponse2(
                        i.toString(),
                        data
                    )
                } as Function<TextTransNewRes?, MultDataResponse2>)
        }

        var fromLang: String? = null
        var toLang: String? = null
        Observable.mergeArray(*observables)
            .subscribeOn(Schedulers.io())
            .compose(RxSchedulers.applySchedulers())
            .subscribe(MultNetDisposableObserver(object :
                MultNetDisposableObserver.NetCallBack {
                private val stringMap = SparseArray<TextTransNewRes>()
                override fun onResponse(response: Any) {
                    if (response is MultDataResponse2) {
                        val index = StringUtils.toInt(response.requestTag, -1)
                        val resp = response.dataResponse as TextTransNewRes
                        if (index != -1) {
                            stringMap.put(index, resp)
                            fromLang = resp.fromLang
                            toLang = resp.toLang
                        }
                    }
                }

                override fun onError(code: Int, msg: String) {
                    if (!isDestroy) {
                        callback?.onTranslateFailed(code, msg)
                    }
                }

                override fun onTokenInvalid(msg: String) {
                    if (!isDestroy) {
                        callback?.onTranslateFailed(Constants.ResponseCode.ERROR_TOKEN, msg)
                    }
                }

                override fun onComplete() {
                    if (!isDestroy) {
                        val contentTranslate = StringBuilder()
                        val alignString = StringBuilder()
                        if (stringMap.size() > 0) {
                            var isDangerous = false
                            var errorMsg = ""
                            var errorCode = 0
                            for (i in 0 until stringMap.size()) {
                                //译文内容拼接
                                val mTextTransNewRes = stringMap[i]
                                if(!mTextTransNewRes.isStatus){
                                    errorMsg = mTextTransNewRes.reason?: mContext.getString(R.string.trans_server_is_busy)
                                    if(errorMsg == "Same lang"){
                                        errorCode = Constants.ResponseCode.ERROR_SAME_LANG
                                        errorMsg = mContext.getString(R.string.trans_same_lang)
                                    }else{
                                        errorCode = Constants.ResponseCode.ERROR_COMM
                                    }
                                }
                                if(i > 0){
                                    contentTranslate.append(" ")
                                }
                                contentTranslate.append(mTextTransNewRes.toText?:"")
                                isDangerous = isDangerous || mTextTransNewRes.isDanger

                                //双语对照内容拼接，按顺序
                                mTextTransNewRes.align?.let {
                                    for (index in 0 until it.size) {
                                        val value = it[index.toString()]
                                        value?.values?.forEach { align ->
                                            if(
                                                align.src.trim().isNotEmpty()
                                                && align.tgt.isNotEmpty()
                                            ){
                                                alignString.append(align.src)
                                                alignString.append("\n")
                                                alignString.append(align.tgt)
                                                alignString.append("\n\n")
                                            }
                                        }
                                    }
                                }

                            }
                            stringMap.clear()
                            val content = contentTranslate.toString()
                            val bilingual = alignString.toString()
                            //空字符拦截
                            if(content.trim().isEmpty()){
                                if(isDangerous){
                                    callback?.onTranslateFailed(
                                        Constants.ResponseCode.ERROR_IS_DANGER,
                                        mContext.getString(R.string.trans_content_error)
                                    )
                                }else{
                                    if(!TextUtils.isEmpty(errorMsg) && errorCode != 0){
                                        callback?.onTranslateFailed(
                                            errorCode,
                                            errorMsg
                                        )
                                    }else{
                                        callback?.onTranslateFailed(
                                            Constants.ResponseCode.ERROR_COMM,
                                            mContext.getString(R.string.trans_server_is_busy)
                                        )
                                    }
                                }
                            }else{
                                logDebug("在线 = $content")
                                callback?.onTranslateCompleted(
                                    content,
                                    fromLang,
                                    toLang,
                                    true)
                            }
                        }
                    }
                }
            }))
    }

    private fun sortByKey(req: TextTransNewReq): String{
        /**排序-拼接-md5*/
        //排序
        val map: MutableMap<String, String> = TreeMap { obj1, obj2 -> // 按照key的升序排序
            obj1?.compareTo(obj2!!)!!
        }
        map["fromLang"] = req.fromLang
        map["toLang"] = req.toLang
        map["fromText"] = req.fromText
        map["withDiff"] = req.withDiff.toString()
        map["timestamp"] = req.timestamp.toString()
        map["fromProduct"] = req.fromProduct

        val keySet: Set<String> = map.keys
        //拼接
        val it = keySet.iterator()
        var splicing = ""
        while (it.hasNext()) {
            val key = it.next()
            splicing += key + map[key]
        }
        splicing += "PONYTRANS2022"
        //md5
        //Log.e("splicing","splicing = $splicing")
        val md5 = Md5Util.md5(splicing)
        //Log.e("splicing","md5 = $md5")
        return md5
    }

    private fun translateOffline(
        origContentAfter: String,
        fromTranslateCode: String,
        toTranslateCode: String,
        callback: TranslateCallback?,
    ){

        val contentList = StringUtils.splitStringByLength(origContentAfter, Constants.MAX_TRANSLATE_SIZE)
        if (contentList.isNullOrEmpty()) {
            callback?.onTranslateFailed(
                Constants.ResponseCode.ERROR_COMM,
                mContext.getString(R.string.tips_empty_content)
            )
            return
        }

        contentList.forEach { content ->
            if(SensitiveWordsCheck.isViolated(content)){
                //违规内容拦截
                callback?.onTranslateFailed(
                    Constants.ResponseCode.ERROR_IS_DANGER,
                    mContext.getString(R.string.trans_content_error)
                )
                return
            }
        }

        val size: Int = contentList.size
        val observables: Array<Observable<*>?> = arrayOfNulls(size)
        for (i in size - 1 downTo 0) {
            observables[i] =
                Observable.create<TransResultBean?>(ObservableOnSubscribe<TransResultBean?> {
                        emit: ObservableEmitter<TransResultBean?> ->
                    offlineManager.translate(
                        contentList[i],
                        fromTranslateCode,
                        toTranslateCode,
                        i
                    ){
                        emit.onNext(it)
                        emit.onComplete()
                    }

                })
                    .map(Function { bean -> bean })
        }
        Observable.mergeArray(*observables)
            .subscribeOn(Schedulers.io())
            .compose(RxSchedulers.applySchedulers())
            .subscribe(OfflineDisposableObserver(object : OfflineDisposableObserver.CallBack {
                private val stringMap = SparseArray<String>()
                override fun onNext(data: Any) {
                    if (data is TransResultBean) {
                        stringMap.put(data.index, data.context)
                    }
                }
                override fun onError(e: Throwable) {
                    if (!isDestroy) {
                        callback?.onTranslateFailed(
                            Constants.ResponseCode.ERROR_COMM,
                            "翻译失败"
                        )
                    }
                }
                override fun onComplete() {
                    if (!isDestroy) {
                        val contentTranslate = java.lang.StringBuilder()
                        if (stringMap.size() > 0) {
                            for (i in 0 until size) {
                                contentTranslate.append(stringMap[i]?:"")
                                contentTranslate.append(" ")
                            }

                            var result = contentTranslate.toString()

                            //违规内容拦截
                            if(SensitiveWordsCheck.isViolated(result)) {
                                callback?.onTranslateFailed(
                                    Constants.ResponseCode.ERROR_IS_DANGER,
                                    mContext.getString(R.string.trans_content_error)
                                )
                                return
                            }

                            //空字符拦截
                            if (result.trim { it <= ' ' }.isEmpty()) {
                                callback?.onTranslateFailed(
                                    Constants.ResponseCode.ERROR_COMM,
                                    mContext.getString(R.string.trans_server_is_busy)
                                )
                                return
                            }
                            logDebug("离线 = $result")
                            callback?.onTranslateCompleted(
                                result,
                                fromTranslateCode,
                                toTranslateCode,
                                true)
                        } else {
                            callback?.onTranslateFailed(
                                Constants.ResponseCode.ERROR_COMM,
                                "翻译失败"
                            )
                        }
                    }
                }
            }))
    }

    private fun logDebug(msg: String){
        if(TranslationInterior.isDebug())
            Log.d("HdTranslateComponent", msg)
    }
}